package com.yan.club.auth.filter;

import com.alibaba.fastjson.JSON;
import com.yan.club.auth.model.LoginUser;
import com.yan.club.auth.utils.WebUtils;
import com.yan.club.result.Result;
import com.yan.club.utils.JwtUtil;
import io.jsonwebtoken.Claims;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.annotation.Resource;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

import static com.yan.club.auth.constant.RedisConstant.LOGIN_KEY;
import static com.yan.club.result.ResultCode.UNAUTHORIZED;

/**
 * @author 彦
 * @since 2024/1/19 15:01
 * 认证过滤器
 */
@Component
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {

        //获取请求头中的token值
        String token = request.getHeader("Authorization");

        //判断上面那行有没有拿到token值
        if (!StringUtils.hasText(token)) {
            //说明该接口不需要登录，直接放行，不拦截
            filterChain.doFilter(request, response);
            return;
        }


        Claims claims;
        try {
            claims = JwtUtil.parseJWT(token);
        } catch (Exception e) {

            // token过期重新登录的情况
            if ("/sys/user/logout".equals(request.getRequestURI())) {
                //说明该接口不需要登录，直接放行，不拦截
                UsernamePasswordAuthenticationToken authenticationToken =
                        new UsernamePasswordAuthenticationToken(null, null, null);
                SecurityContextHolder.getContext().setAuthentication(authenticationToken);
                return;
            }

            //当token过期或token被篡改就会进入下面那行的异常处理
            e.printStackTrace();
            //报异常之后，把异常响应给前端，需要重新登录。
            Result<String> result = Result.error(UNAUTHORIZED.code, "用户未登录！");
            WebUtils.renderString(response, JSON.toJSONString(result));
            return;
        }
        String userId = claims.getSubject();

        String loginUserJson = stringRedisTemplate.opsForValue().get(LOGIN_KEY + userId);
        //如果在redis获取不到值，说明登录是过期了，需要重新登录
        if (StringUtils.isEmpty(loginUserJson)) {

            // token过期重新登录的情况
            if ("/sys/user/logout".equals(request.getRequestURI())) {
                //说明该接口不需要登录，直接放行，不拦截
                SecurityContextHolder.getContext().setAuthentication(null);
                return;
            }

            Result<String> result = Result.error(UNAUTHORIZED.code, "用户未登录！");
            WebUtils.renderString(response, JSON.toJSONString(result));
            return;
        }

        LoginUser loginUser = JSON.parseObject(loginUserJson, LoginUser.class);
        //把从redis获取到的value，存入到SecurityContextHolder,三个参数才是认证后的
        UsernamePasswordAuthenticationToken authenticationToken =
                new UsernamePasswordAuthenticationToken(loginUser, null, loginUser.getAuthorities());
        SecurityContextHolder.getContext().setAuthentication(authenticationToken);

        filterChain.doFilter(request, response);
    }
}